/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997, 1998, 1999  Sam Lantinga

    This library is SDL_free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Sam Lantinga
    slouken@devolution.com
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <SDL/SDL.h>
#include "SDL_sysvideo.h"
#include "SDL_blit.h"
#include "SDL_RLEaccel_c.h"
#include "SDL_pixels_c.h"

/* Public routines */
/*
 * Create an empty RGB surface of the appropriate depth
 */
SDL_Surface * SDL_CreateRGBSurface (Uint32 flags,
			int width, int height, int depth,
			Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this  = current_video;
	SDL_Surface *screen;
	SDL_Surface *surface;

	/* Check to see if we desire the surface in video memory */
	if ( video ) {
		screen = SDL_PublicSurface;
	} else {
		screen = NULL;
	}
	if ( screen && ((screen->flags&SDL_HWSURFACE) == SDL_HWSURFACE) ) {
		if ( (flags&(SDL_SRCCOLORKEY|SDL_SRCALPHA)) != 0 ) {
			flags |= SDL_HWSURFACE;
		}
		if ( (flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
			if ( ! current_video->info.blit_hw_CC ) {
				flags &= ~SDL_HWSURFACE;
			}
		}
		if ( (flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
			if ( ! current_video->info.blit_hw_A ) {
				flags &= ~SDL_HWSURFACE;
			}
		}
	} else {
		flags &= ~SDL_HWSURFACE;
	}

	/* Allocate the surface */
	surface = (SDL_Surface *)SDL_malloc(sizeof(*surface));
	if ( surface == NULL ) {
		SDL_OutOfMemory();
		return(NULL);
	}
	surface->flags = SDL_SWSURFACE;
	if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
		depth = screen->format->BitsPerPixel;
		Rmask = screen->format->Rmask;
		Gmask = screen->format->Gmask;
		Bmask = screen->format->Bmask;
		Amask = screen->format->Amask;
	}
	surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
	if ( surface->format == NULL ) {
		SDL_free(surface);
		return(NULL);
	}
	if ( Amask ) {
		surface->flags |= SDL_SRCALPHA;
	}
	surface->w = width;
	surface->h = height;
	surface->pitch = SDL_CalculatePitch(surface);
	surface->pixels = NULL;
	surface->offset = 0;
	surface->hwdata = NULL;
	surface->map = NULL;
	surface->mapped = NULL;
	SDL_SetClipping(surface, 0, 0, 0, 0);

	/* Get the pixels */
	if ( ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) || 
				(video->AllocHWSurface(this, surface) < 0) ) {
		if ( surface->w && surface->h ) {
			surface->pixels = SDL_malloc(surface->h*surface->pitch);
			if ( surface->pixels == NULL ) {
				SDL_FreeSurface(surface);
				SDL_OutOfMemory();
				return(NULL);
			}
			/* This is important for bitmaps */
			memset(surface->pixels, 0, surface->h*surface->pitch);
		}
	}

	/* Allocate an empty mapping */
	surface->map = SDL_AllocBlitMap();
	if ( surface->map == NULL ) {
		SDL_FreeSurface(surface);
		return(NULL);
	}

	/* The surface is ready to go */
	surface->refcount = 1;
#ifdef CHECK_LEAKS
	++surfaces_allocated;
#endif
	return(surface);
}
/*
 * Create an RGB surface from an existing memory buffer
 */
SDL_Surface * SDL_CreateRGBSurfaceFrom (void *pixels,
			int width, int height, int depth, int pitch,
			Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
	SDL_Surface *surface;

	surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, depth,
	                               Rmask, Gmask, Bmask, Amask);
	if ( surface != NULL ) {
		surface->flags |= SDL_PREALLOC;
		surface->pixels = pixels;
		surface->w = width;
		surface->h = height;
		surface->pitch = pitch;
	}
	return(surface);
}
/*
 * Set the color key in a blittable surface
 */
int SDL_SetColorKey (SDL_Surface *surface, Uint32 flag, Uint32 key)
{
	if ( flag ) {
		SDL_VideoDevice *video = current_video;
		SDL_VideoDevice *this  = current_video;

		surface->flags |= SDL_SRCCOLORKEY;
		surface->format->colorkey = key;
		if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
			if ( (video->SetHWColorKey == NULL) ||
			     (video->SetHWColorKey(this, surface, key) < 0) ) {
				surface->flags &= ~SDL_HWACCEL;
			}
		}
		if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
			surface->flags |= SDL_RLEACCELOK;
		}
	} else {
		surface->flags &= ~(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
		surface->format->colorkey = 0;
	}
	SDL_InvalidateMap(surface->map);
	return(0);
}
int SDL_SetAlpha (SDL_Surface *surface, Uint32 flag, Uint8 value)
{
	if ( flag ) {
		SDL_VideoDevice *video = current_video;
		SDL_VideoDevice *this  = current_video;

		surface->flags |= SDL_SRCALPHA;
		surface->format->alpha = value;
		if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
			if ( (video->SetHWAlpha == NULL) ||
			     (video->SetHWAlpha(this, surface, value) < 0) ) {
				surface->flags &= ~SDL_HWACCEL;
			}
		}
	} else {
		surface->flags &= ~SDL_SRCALPHA;
		surface->format->alpha = 0;
	}
	SDL_InvalidateMap(surface->map);
	return(0);
}
/*
 * Set the clipping rectangle for a blittable surface
 */
void SDL_SetClipping (SDL_Surface *surface,
			int top, int left, int bottom, int right)
{
	/* Set the clipping rectangle and flags */
	if ( top || left || bottom || right ) {
		surface->clip_minx = left;
		surface->clip_miny = top;
		surface->clip_maxx = right;
		surface->clip_maxy = bottom;
		surface->flags |= SDL_SRCCLIPPING;
	} else {
		surface->clip_minx = 0;
		surface->clip_miny = 0;
		surface->clip_maxx = surface->w-1;
		surface->clip_maxy = surface->h-1;
		surface->flags &= ~SDL_SRCCLIPPING;
	}
}
/* 
 * Set up a blit between two surfaces -- split into three parts:
 * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
 * verification.  The lower part is a pointer to a low level
 * accelerated blitting function.
 *
 * These parts are separated out and each used internally by this 
 * library in the optimimum places.  They are exported so that if
 * you know exactly what you are doing, you can optimize your code
 * by calling the one(s) you need.
 */
int SDL_LowerBlit (SDL_Surface *src, SDL_Rect *srcrect,
				SDL_Surface *dst, SDL_Rect *dstrect)
{
	SDL_blit do_blit;

	/* Check to make sure the blit mapping is valid */
	if ( src->map->dst != dst ) {
		if ( SDL_MapSurface(src, dst) < 0 ) {
			return(-1);
		}
	}

	/* Figure out which blitter to use */
	if ( (src->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
		do_blit = src->map->hw_blit;
	} else {
		do_blit = src->map->sw_blit;
	}
	return(do_blit(src, srcrect, dst, dstrect));
}
int SDL_UpperBlit (SDL_Surface *src, SDL_Rect *srcrect,
					SDL_Surface *dst, SDL_Rect *dstrect)
{
	SDL_Rect fullsrc, fulldst;
	int clip_diff;

	/* Set default rectangles */
	if ( dstrect == NULL ) {
		fulldst.x = 0;
		fulldst.y = 0;
		fulldst.w = dst->w;
		fulldst.h = dst->h;
		dstrect = &fulldst;
	}
	if ( srcrect == NULL ) {
		fullsrc.x = 0;
		fullsrc.y = 0;
		fullsrc.w = src->w;
		fullsrc.h = src->h;
		srcrect = &fullsrc;
	}

	/* Verify the destination coordinates */
	if ( dstrect != &fulldst ) {

		/* Check for negative destination coordinates */
		if ( dstrect->x < 0 ) {
			if ( -dstrect->x >= dstrect->w ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
			srcrect->x -= dstrect->x;
			srcrect->w += dstrect->x;
			dstrect->w += dstrect->x;
			dstrect->x = 0;
		}
		if ( dstrect->y < 0 ) {
			if ( -dstrect->y >= dstrect->h ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
			srcrect->y -= dstrect->y;
			srcrect->h += dstrect->y;
			dstrect->h += dstrect->y;
			dstrect->y = 0;
		}

		/* Check for overlarge destination rectangle */
		clip_diff = (dstrect->x+dstrect->w)-(dst->w);
		if ( clip_diff > 0 ) {
			if ( clip_diff >= dstrect->w ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
			dstrect->w -= clip_diff;
			srcrect->w -= clip_diff;
		}
		clip_diff = (dstrect->y+dstrect->h)-(dst->h);
		if ( clip_diff > 0 ) {
			if ( clip_diff >= dstrect->h ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
			dstrect->h -= clip_diff;
			srcrect->h -= clip_diff;
		}
	}

	/* Verify the source coordinates */
	if ( srcrect != &fullsrc ) {

		/* Check for negative destination coordinates */
		if ( srcrect->x < 0 ) {
			if ( -srcrect->x >= srcrect->w ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
			srcrect->w += srcrect->x;
			dstrect->w += srcrect->x;
			srcrect->x = 0;
		}
		if ( srcrect->y < 0 ) {
			if ( -srcrect->y >= srcrect->h ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
			srcrect->h += srcrect->y;
			dstrect->h += srcrect->y;
			srcrect->y = 0;
		}

		/* Check for overlarge source rectangle */
		clip_diff = (srcrect->x+srcrect->w)-(src->w);
		if ( clip_diff > 0 ) {
			if ( clip_diff >= dstrect->w ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
			dstrect->w -= clip_diff;
			srcrect->w -= clip_diff;
		}
		clip_diff = (srcrect->y+srcrect->h)-(src->h);
		if ( clip_diff > 0 ) {
			if ( clip_diff >= dstrect->h ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
			dstrect->h -= clip_diff;
			srcrect->h -= clip_diff;
		}
	}

	/* Check for clipping */
	if ( (src->flags & SDL_SRCCLIPPING) == SDL_SRCCLIPPING ) {

		/* Check for clipping and adjust rectangles */
		clip_diff = src->clip_minx-dstrect->x;
		if ( clip_diff > 0 ) {
			if ( clip_diff >= dstrect->w ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
#ifdef DEBUG_BLIT
 fprintf(stderr, 
	"Blit of %dx%d at (%d,%d) extends %d pixels beyond left edge\n", 
		dstrect->w, dstrect->h, dstrect->x, dstrect->y, clip_diff);
#endif
			dstrect->x += clip_diff;
			dstrect->w -= clip_diff;
			srcrect->x += clip_diff;
			srcrect->w -= clip_diff;
		}
		clip_diff = (dstrect->x+dstrect->w)-src->clip_maxx;
		if ( clip_diff > 0 ) {
			if ( clip_diff >= dstrect->w ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
#ifdef DEBUG_BLIT
 fprintf(stderr,
	"Blit of %dx%d at (%d,%d) extends %d pixels beyond right edge (%d)\n", 
		dstrect->w, dstrect->h, dstrect->x, dstrect->y, clip_diff,
								src->clip_maxx);
#endif
			dstrect->w -= clip_diff;
			srcrect->w -= clip_diff;
		}
		clip_diff = src->clip_miny-dstrect->y;
		if ( clip_diff > 0 ) {
			if ( clip_diff >= dstrect->h ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
#ifdef DEBUG_BLIT
 fprintf(stderr,
	"Blit of %dx%d at (%d,%d) extends %d pixels beyond top edge\n", 
		dstrect->w, dstrect->h, dstrect->x, dstrect->y, clip_diff);
#endif
			dstrect->y += clip_diff;
			dstrect->h -= clip_diff;
			srcrect->y += clip_diff;
			srcrect->h -= clip_diff;
		}
		clip_diff = (dstrect->y+dstrect->h)-src->clip_maxy;
		if ( clip_diff > 0 ) {
			if ( clip_diff >= dstrect->h ) {
				srcrect->w = srcrect->h = 0;
				dstrect->w = dstrect->h = 0;
				return(0);
			}
#ifdef DEBUG_BLIT
 fprintf(stderr,
	"Blit of %dx%d at (%d,%d) extends %d pixels beyond bottom edge\n", 
		dstrect->w, dstrect->h, dstrect->x, dstrect->y, clip_diff);
#endif
			dstrect->h -= clip_diff;
			srcrect->h -= clip_diff;
		}
	}

	/* Check to make sure the blit rectangles are valid */
	if ( (srcrect->w != dstrect->w) || (srcrect->h != dstrect->h) ) {
		SDL_SetError("SDL_UpperBlit: Passed mismatched rectangles");
		return(-1);
	}

#ifdef DEBUG_BLIT
 fprintf(stderr, "UpperBlit %dx%d from 0x%p, (%d,%d) to 0x%p, (%d,%d) ... \n",
					srcrect->w, srcrect->h,
					src->pixels, srcrect->x, srcrect->y,
					dst->pixels, dstrect->x, dstrect->y);
#endif
	/* Do the blit */
	return(SDL_LowerBlit(src, srcrect, dst, dstrect));
}

/* 
 * This function performs a fast fill of the given rectangle with 'color'
 */
int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this  = current_video;
	SDL_Rect fullrect;
	int x, y;
	Uint8 *row;

	/* If 'dstrect' == NULL, then fill the whole surface */
	if ( dstrect == NULL ) {
		fullrect.x = 0;
		fullrect.y = 0;
		fullrect.w = dst->w;
		fullrect.h = dst->h;
		dstrect = &fullrect;
	} else {
		/* Perform clipping */
		if ( dstrect->x < 0 ) {
			if ( -dstrect->x >= dstrect->w ) {
				return(0);
			}
			dstrect->w += dstrect->x;
			dstrect->x = 0;
		}
		if ( dstrect->y < 0 ) {
			if ( -dstrect->y >= dstrect->h ) {
				return(0);
			}
			dstrect->h += dstrect->y;
			dstrect->y = 0;
		}
		if ( dstrect->x+dstrect->w > dst->w ) {
			if ( dstrect->x >= dst->w ) {
				return(0);
			}
			dstrect->w = dst->w-dstrect->x;
		}
		if ( dstrect->y+dstrect->h > dst->h ) {
			if ( dstrect->y >= dst->h ) {
				return(0);
			}
			dstrect->h = dst->h-dstrect->y;
		}
	}

	/* Check for hardware acceleration */
	if ( ((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) &&
					video->info.blit_fill ) {
		return(video->FillHWRect(this, dst, dstrect, color));
	}

	/* Perform software fill */
	if ( SDL_LockSurface(dst) != 0 ) {
		return(-1);
	}
	row = (Uint8 *)dst->pixels+dstrect->y*dst->pitch+
			dstrect->x*dst->format->BytesPerPixel;
	if ( dst->format->palette || (color == 0) ) {
		x = dstrect->w*dst->format->BytesPerPixel;
		for ( y=dstrect->h; y; --y ) {
#ifdef __powerpc__	/* SIGBUS when using memset() ?? */
			if ( color ) {
				Uint8 *rowp = row;
				int left = x;
				while ( left-- ) { *rowp++ = color; }
			} else {
				Uint8 *rowp = row;
				int left = x;
				while ( left-- ) { *rowp++ = 0; }
			}
#else
			memset(row, color, x);
#endif
			row += dst->pitch;
		}
	} else {
		switch (dst->format->BytesPerPixel) {
		    case 2: {
			Uint16 *pixels;
			for ( y=dstrect->h; y; --y ) {
				pixels = (Uint16 *)row;
				for ( x=dstrect->w/4; x; --x ) {
					*pixels++ = color;
					*pixels++ = color;
					*pixels++ = color;
					*pixels++ = color;
				}
				switch (dstrect->w%4) {
					case 3:
						*pixels++ = color;
					case 2:
						*pixels++ = color;
					case 1:
						*pixels++ = color;
				}
				row += dst->pitch;
			}
		    }
		    break;

		    case 3: {
			Uint8 *pixels;
			for ( y=dstrect->h; y; --y ) {
				pixels = row;
				for ( x=dstrect->w; x; --x ) {
					memcpy(pixels, &color, 3);
					pixels += 3;
				}
				row += dst->pitch;
			}
		    }
		    break;

		    case 4: {
			Uint32 *pixels;
			for ( y=dstrect->h; y; --y ) {
				pixels = (Uint32 *)row;
				for ( x=dstrect->w/4; x; --x ) {
					*pixels++ = color;
					*pixels++ = color;
					*pixels++ = color;
					*pixels++ = color;
				}
				switch (dstrect->w%4) {
					case 3:
						*pixels++ = color;
					case 2:
						*pixels++ = color;
					case 1:
						*pixels++ = color;
				}
				row += dst->pitch;
			}
		    }
		    break;
		}
	}
	SDL_UnlockSurface(dst);

	/* We're done! */
	return(0);
}

/*
 * Lock a surface to directly access the pixels
 * -- Do not call this from any blit function, as SDL_DrawCursor() may recurse
 *    Instead, use:
 *    if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )
 *               video->LockHWSurface(video, surface);
 */
int SDL_LockSurface (SDL_Surface *surface)
{
	/* Perform the lock */
	if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
		SDL_VideoDevice *video = current_video;
		SDL_VideoDevice *this  = current_video;
		if ( video->LockHWSurface(this, surface) < 0 ) {
			return(-1);
		}
	}
	surface->pixels = (Uint8 *)surface->pixels + surface->offset;
	return(0);
}
/*
 * Unlock a previously locked surface
 * -- Do not call this from any blit function, as SDL_DrawCursor() may recurse
 *    Instead, use:
 *    if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )
 *               video->UnlockHWSurface(video, surface);
 */
void SDL_UnlockSurface (SDL_Surface *surface)
{
	/* Perform the unlock */
	surface->pixels = (Uint8 *)surface->pixels - surface->offset;

	/* Unlock hardware or accelerated surfaces */
	if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
		SDL_VideoDevice *video = current_video;
		SDL_VideoDevice *this  = current_video;
		video->UnlockHWSurface(this, surface);
	} else {
		/* Update RLE encoded surface with new data */
		if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
			SDL_RLESurface(surface);
		}
	}
}

/* 
 * Convert a surface into the specified pixel format.
 */
SDL_Surface * SDL_ConvertSurface (SDL_Surface *surface,
					SDL_PixelFormat *format, Uint32 flags)
{
	SDL_Surface *convert;
	Uint32 colorkey;
	Uint8 alpha;
	Uint32 surface_flags;
	SDL_Rect bounds;

	/* Check for empty destination palette! (results in empty image) */
	if ( format->palette != NULL ) {
		int i;
		for ( i=0; i<format->palette->ncolors; ++i ) {
			if ( (format->palette->colors[i].r != 0) ||
			     (format->palette->colors[i].g != 0) ||
			     (format->palette->colors[i].b != 0) )
				break;
		}
		if ( i == format->palette->ncolors ) {
			SDL_SetError("Empty destination palette");
			return(NULL);
		}
	}

	/* Create a new surface with the desired format */
	convert = SDL_CreateRGBSurface(flags,
				surface->w, surface->h, format->BitsPerPixel,
		format->Rmask, format->Gmask, format->Bmask, format->Amask);
	if ( convert == NULL ) {
		return(NULL);
	}

	/* Copy the palette if any */
	if ( format->palette ) {
		memcpy(convert->format->palette->colors,
				format->palette->colors,
				format->palette->ncolors*sizeof(SDL_Color));
	}

	/* Save the original surface clipping, color key and alpha */
	surface_flags = surface->flags;
	if ( (surface_flags & SDL_SRCCLIPPING) == SDL_SRCCLIPPING ) {
		SDL_SetClipping(convert,surface->clip_minx,surface->clip_maxx,
					surface->clip_miny,surface->clip_maxy);
	}
	if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
		colorkey = surface->format->colorkey;
		SDL_SetColorKey(surface, 0, 0);
	}
	if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
		alpha = surface->format->alpha;
		SDL_SetAlpha(surface, 0, 0);
	}

	/* Copy over the image data */
	bounds.x = 0;
	bounds.y = 0;
	bounds.w = surface->w;
	bounds.h = surface->h;
	SDL_LowerBlit(surface, &bounds, convert, &bounds);

	/* Clean up the original surface, and update converted surface */
	if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
		if ( convert != NULL ) {
			Uint8 keyR, keyG, keyB;

			SDL_GetRGB(colorkey,surface->format,&keyR,&keyG,&keyB);
			SDL_SetColorKey(convert, 
				surface_flags&(SDL_SRCCOLORKEY|SDL_RLEACCELOK), 
				SDL_MapRGB(convert->format, keyR, keyG, keyB));
		}
		SDL_SetColorKey(surface, 
				surface_flags&(SDL_SRCCOLORKEY|SDL_RLEACCELOK), 
								colorkey);
	}
	if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
		if ( convert != NULL ) {
			SDL_SetAlpha(convert,surface_flags&SDL_SRCALPHA,alpha);
		}
		SDL_SetAlpha(surface, surface_flags&SDL_SRCALPHA, alpha);
	}

	/* We're ready to go! */
	return(convert);
}

/*
 * Free a surface created by the above function.
 */
void SDL_FreeSurface (SDL_Surface *surface)
{
	/* Free anything that's not NULL, and not the screen surface */
	if ((surface == NULL) ||
	    (current_video &&
	    ((surface == SDL_ShadowSurface)||(surface == SDL_VideoSurface)))) {
		return;
	}
	if ( --surface->refcount > 0 ) {
		return;
	}
	if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
		SDL_UnRLESurface(surface);
	}
	if ( surface->format ) {
		SDL_FreeFormat(surface->format);
		SDL_FormatChanged(surface);
		surface->format = NULL;
	}
	if ( surface->map != NULL ) {
		SDL_FreeBlitMap(surface->map);
		surface->map = NULL;
	}
	if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
		SDL_VideoDevice *video = current_video;
		SDL_VideoDevice *this  = current_video;
		video->FreeHWSurface(this, surface);
	}
	if ( surface->pixels &&
	     ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC) ) {
		SDL_free(surface->pixels);
	}
	SDL_free(surface);
#ifdef CHECK_LEAKS
	--surfaces_allocated;
#endif
}
